#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>

/*
void printsig(sigset_t &pending)
{
    std::cout << "pending bitmap: ";
    for (int signum = 31; signum >= 1; signum--)
    {
        if (sigismember(&pending, signum))
        {
            std::cout << "1 ";
        }
        else
        {
            std::cout << "0 ";
        }
    }
    std::cout << std::endl;
}

void handler(int signum)
{
    std::cout << "signal: " << signum << std::endl;
    sigset_t pending;
    sigemptyset(&pending);
    while (true)
    {
        sigpending(&pending);
        printsig(pending);
        sleep(1);
    }
}

int main()
{
    std::cout << "pid: " << getpid() << std::endl;
    struct sigaction act, oldact;
    act.sa_flags = 0;
    act.sa_handler = handler;
    sigemptyset(&(act.sa_mask));
    sigaddset(&(act.sa_mask),3);
    sigaddset(&(act.sa_mask),4);
    sigaddset(&(act.sa_mask),5);
    sigaction(SIGINT, &act, &oldact);
    while (true)
    {
        sleep(1);
    }
    return 0;
}
*/

// 子进程退出时会给父进程发送SIGCHLD信号,父进程不退出,进行捕捉验证
void handler(int signum)
{
    std::cout << "child quit, father get a signal: " << signum << std::endl;
}

// 1.创建的子进程个数只有1个

/*
 void CleanupChild(int signum)
{
    //子进程退出时,子进程会给父进程发送SIGCHLD信号
    //父进程的自定义捕捉函数中进行子进程的回收,父进程便可专心处理自己的任务
    if(signum==SIGCHLD)
    {
        pid_t rid=waitpid(-1,nullptr,0);//阻塞式等待任意一个子进程,但是此处不会阻塞
        if(rid>0)
        {
            std::cout<<"wait child process:"<<rid<<std::endl;
        }

    }
    std::cout<<"wait sub process done!"<<std::endl;
}
int main()
{
    signal(SIGCHLD, CleanupChild);

    pid_t id=fork();
    if(id==0)
    {

        //child process
        int cnt=10;
        while(cnt)
        {
            std::cout<<"I am child process,pid: "<<getpid()<<std::endl;
            sleep(1);
            cnt--;
        }
        std::cout<<"child process Quit"<<std::endl;
        exit(0);
    }

    //father process
    while(true)
    {
        sleep(1);
    }
    return 0;
}
*/

// 2.父进程创建多个子进程,当其中一个子进程退出时父进程收到SIGCHLD信号,执行自定义捕捉函数,同时会将该信号添加到信号屏蔽字
// 此时其他子进程退出时发送SIGCHLD信号全部没有被递达处理,导致这些子进程变为僵尸进程
// 信号处理函数中进行循环式回收
void CleanupChild(int signum)
{
    if (signum == SIGCHLD)
    {
        while (true)
        {
            pid_t rid = waitpid(-1, nullptr, WNOHANG); // 非阻塞式等待任意一个子进程
            if (rid > 0)
            {
                std::cout << "wait child process:" << rid << std::endl;
            }
            else 
            {
                break;
            }
        }
    }
    std::cout << "wait sub process done!" << std::endl;
}

int main()
{
    signal(SIGCHLD, CleanupChild);

    for (int i = 0; i < 10; i++)
    {
        pid_t id = fork();
        if (id == 0)
        {

            // child process
            int cnt = 10;
            while (cnt)
            {
                std::cout << "I am child process,pid: " << getpid() << std::endl;
                sleep(1);
                cnt--;
            }
            std::cout << "child process Quit" << std::endl;
            exit(0);
        }
    }
    // father process
    while (true)
    {
        sleep(1);
    }
    return 0;
}
